﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LemonAlgorithm.SkylineAlgorithm
{
    public class ConstrainedSkylinePacker : SkylinePacker
    {
        private List<Rectangle> forbiddenAreas;

        public ConstrainedSkylinePacker(float containerWidth, float containerHeight,
                                      float wallClearance = 0f)
            : base(containerWidth, containerHeight, wallClearance)
        {
            forbiddenAreas = new List<Rectangle>();
        }

        public void AddForbiddenArea(Rectangle area)
        {
            forbiddenAreas.Add(area);
        }

        // 重写寻找最佳放置位置的方法，添加约束检查
        protected override PlacementCandidate FindBestPlacement(Rectangle rect)
        {
            var candidates = new List<PlacementCandidate>();

            for (int i = 0; i < skyline.Count; i++)
            {
                var segment = skyline[i];
                if (!segment.IsAvailable) continue;

                // 尝试不旋转
                var candidate = TryCreatePlacementCandidate(i, rect, false);
                if (candidate != null && !OverlapsForbiddenArea(candidate, rect.Width, rect.Height))
                {
                    candidates.Add(candidate);
                }

                // 尝试旋转
                if (rect.CanRotate)
                {
                    candidate = TryCreatePlacementCandidate(i, rect, true);
                    if (candidate != null && !OverlapsForbiddenArea(candidate, rect.Height, rect.Width))
                    {
                        candidates.Add(candidate);
                    }
                }
            }

            return candidates.OrderBy(c => c.Waste).FirstOrDefault();
        }

        private PlacementCandidate TryCreatePlacementCandidate(int segmentIndex, Rectangle rect, bool rotate)
        {
            float width = rotate ? rect.Height : rect.Width;
            float height = rotate ? rect.Width : rect.Height;

            var segment = skyline[segmentIndex];

            if (segment.Width < width) return null;

            float placementY = segment.Y;
            if (placementY + height > containerHeight - wallClearance) return null;

            if (!CheckHorizontalSpace(segment.X, segmentIndex, width)) return null;

            float waste = CalculateWaste(segmentIndex, segment.X, width, placementY);
            return new PlacementCandidate(segmentIndex, segment.X, placementY, waste, rotate);
        }

        private bool OverlapsForbiddenArea(PlacementCandidate candidate, float width, float height)
        {
            // 使用四个参数的构造函数
            var testRect = new Rectangle(candidate.X, candidate.Y, width, height);
            return OverlapsForbiddenArea(testRect);
        }

        private bool OverlapsForbiddenArea(Rectangle rect)
        {
            foreach (var area in forbiddenAreas)
            {
                if (RectanglesOverlap(rect, area))
                    return true;
            }
            return false;
        }

        private bool RectanglesOverlap(Rectangle a, Rectangle b)
        {
            return a.X < b.X + b.Width &&
                   a.X + a.Width > b.X &&
                   a.Y < b.Y + b.Height &&
                   a.Y + a.Height > b.Y;
        }

        // 重写水平空间检查来添加约束
        protected override bool CheckHorizontalSpace(float startX, int startSegmentIndex, float requiredWidth)
        {
            if (!base.CheckHorizontalSpace(startX, startSegmentIndex, requiredWidth))
                return false;

            // 检查是否与禁止区域重叠
            float currentY = skyline[startSegmentIndex].Y;
            // 使用四个参数的构造函数
            Rectangle testRect = new Rectangle(startX, currentY, requiredWidth, 1f);

            return !OverlapsForbiddenArea(testRect);
        }
    }
}
